home *** CD-ROM | disk | FTP | other *** search
- /* pause.c
- // Contributed by Bill Gatliff, Owensboro KY
- // CompuServe ID: 72630,3653 voice 502-684-5352 (as of 12 Oct '93)
- //
- // Routines associated with a fairly-precise delay timer that is
- // "interrupt friendly."
- //
- // The timer doesn't take into account function-call overhead,
- // so the delay will always run slightly long.
- //
- // According to the IBM PC/XT Technical reference, Timer 0 is run
- // in Mode 3, and is initialized with a reload value of 0xffff,
- // which will cause the 8253 to generate interrupts with a
- // periodicity of 53msec.
- // I adjust that reload value to 0xffffU/53, which will generate
- // interrupts every 1 msec. I then call the BIOS Timer 0 ISR
- // every 53 interrupts to update the system clock, floppy drive, etc.
- //
- // This module contains the following procedures:
- //
- // void interrupt msecDelayISR( void );
- // void interrupt (*oldISR )( void );
- // int initDelay( void );
- // void deinitDelay( void );
- // void msecDelay( unsigned int msecs );
- // unsigned int getTimerCount( void );
- //
- // initDelay() sets up the ISR, etc. It's called automatically
- // the first time msecDelay() is called.
- //
- // deinitDelay() is called automatically at program exit,
- // but may be called beforehand without damage.
- //
- // msecDelay( unsigned int msecs ) suspends foreground execution
- // for _msecs_ milliseconds.
- //
- // getTimerCount() returns the current internal TimerCount value.
- //
- // msecDelayISR() is the interrupt-service-routine that overtakes
- // the standard BIOS timer hardware interrupt without corrupting
- // the system clock. System time should not be significantly
- // effected by the use of these routines.
- //
- // Programmer Date Modification
- // ---------------------------------------------------------------------
- // bg 11 Oct 93 Created Original
- // bg 12 Oct 93 Added msecTimeout,msecExpired
- */
- #include <conio.h>
- #include <dos.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- #define BIOSTimerAddr ((long far*)0x40006cL)
- #define TimerIRQ 0x08 /* Timer 0 IRQ number */
- #define TimerCtrlPort 0x43 /* Control port for Timer 0 */
- #define TimerReloadPort 0x40 /* Register port for Timer 0 */
- #define TimerReloadVal 0x0FFFFU/53 /* Reload value for 1msec delay */
-
- void interrupt msecDelayISR( void );
- void interrupt (*oldISR )( void );
- int initDelay( void );
- void deinitDelay( void );
- void msecDelay( unsigned int msecs );
- int msecExpired( unsigned long timeOutTime );
-
- static volatile unsigned int IRQCounter =0;
- static volatile unsigned int TimerCount =0;
- static char delayInit =0;
-
- /*
- // This procedure hangs out for _msecs_ milliseconds.
- // There's no need to disable interrupts while adjusting TimerCount,
- // since even the XT (I think) can handle 16 bits in a single instruction
- // cycle, which by definition isn't interruptable.
- */
- void msecDelay( unsigned int msecs )
- {
- if( !delayInit )
- if( !initDelay() )
- return;
-
- TimerCount =0;
- while( TimerCount < msecs );
- }
-
- /*
- // This procedure returns the TimerCount value.
- //
- */
- unsigned int getTimerCount( void )
- {
- return TimerCount;
- }
-
- /*
- // initDelay -- initializes the delay timer.
- // Returns 1 on success, 0 if initialization fails.
- // Initialization will fail if atexit() fails.
- */
- int initDelay( void )
- {
- int retVal;
-
- /* don't initialize again! */
- if( delayInit )
- return 1;
-
- delayInit =1;
- oldISR =getvect( TimerIRQ );
- setvect( TimerIRQ,msecDelayISR );
- if( atexit( deinitDelay ) != 0 )
- {
- deinitDelay();
- retVal =0;
- }
- else
- {
- /* reload the timer for 1 msec delay */
- _disable();
- outportb( TimerCtrlPort,0x36 );
- outportb( TimerReloadPort,TimerReloadVal );
- outportb( TimerReloadPort,TimerReloadVal >> 8 );
- _enable();
- retVal =1;
- }
- return retVal;
- }
-
-
- /*
- // Timer 0 Interrupt Service routine.
- // Merely updates TimerCount (every msec), and executes the
- // system clock every 53 msec (approx).
- // Compile WITHOUT stack-overflow checking.
- */
- #pragma -N-
- void interrupt msecDelayISR( void )
- {
- /* clear the interrupt request */
- asm mov al,20h
- asm out 20h,al
-
- /* update our 1msec timer */
- TimerCount++;
-
- /* need to update system clock? */
- if( ++IRQCounter >=52 )
- {
- IRQCounter =0;
- _chain_intr( oldISR );
- }
- }
- #pragma -N.
-
- /*
- // Procedure to restore Timer 0 to it's default state.
- */
- void deinitDelay( void )
- {
- if( !delayInit )
- return;
-
- /* don't deinit twice! */
- delayInit =0;
-
- /* restore old ISR */
- _disable();
- setvect( TimerIRQ,oldISR );
-
- /* reset timer for 53msec delay */
- outportb( TimerCtrlPort,0x36 );
- outportb( TimerReloadPort,0 );
- outportb( TimerReloadPort,0 );
- _enable();
- }
-
- #ifdef KILL
- /*
- // Test procedure.
- */
- #include <time.h>
- int main( void )
- {
- clock_t curTime,startTime;
-
- msecDelay( 0 );
-
- startTime =clock() /CLK_TCK;
- fprintf( stdout,"\nPausing for 10 seconds...\n" );
- while(( curTime =clock() / CLK_TCK ) < startTime + 10 )
- fprintf( stdout,"%d\r",TimerCount );
-
- return 1;
- }
- #endif
-